using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using TowerDefense.Towers;
using TowerDefense.Units;
using TowerDefense.Debuffs;

namespace TowerDefense
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class TDGame : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        ButtonState MouseLastLeftButtonState = ButtonState.Released;
        ButtonState MouseLastRightButtonState = ButtonState.Released;
        bool KeyboardMLastState = false;

        private GameState _gameState;

        #region --- Font fields ---

        SpriteFont sFont;
        Vector2 sFontPos;

        #endregion

        Vector2 markPosition = new Vector2(0, 0);
        public static Texture2D markTexture;
        public static Dictionary<string, Texture2D> textures = new Dictionary<string, Texture2D>();

        public TDGame()
        {
            graphics = new GraphicsDeviceManager(this);
            
            Content.RootDirectory = "Content";

            _gameState = GameState.TitleScreen;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            this.IsMouseVisible = true;

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            textures.Add("gras", this.Content.Load<Texture2D>("../TowerDefenseContent/gras"));
            textures.Add("Mark", this.Content.Load<Texture2D>("../TowerDefenseContent/Mark"));
            textures.Add("road", this.Content.Load<Texture2D>("../TowerDefenseContent/road"));
            textures.Add("pacman", this.Content.Load<Texture2D>("../TowerDefenseContent/pacmanCreep"));
            textures.Add("tower", this.Content.Load<Texture2D>("../TowerDefenseContent/tower"));
            textures.Add("missile1", this.Content.Load<Texture2D>("../TowerDefenseContent/missile1"));
            textures.Add("vulcan-shot", this.Content.Load<Texture2D>("../TowerDefenseContent//vulcan-shot"));

            sFont = this.Content.Load<SpriteFont>("../TowerDefenseContent/SpriteFont1");

            sFontPos = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2,
                                   graphics.GraphicsDevice.Viewport.Height - 100);

            MapRoute mr = new MapRoute();

            List<Level> levels = new List<Level>();
            Map m = new Map(mr, levels, new Vector2(10,10), new Vector2(780, 580));

            for (int y = 0; y < 16; y++)
            {
                for (int x = 0; x < 16; x++)
                {
                    if (y != 8)
                        m.Areas[x, y] = new Area(textures["gras"], true);
                    else
                        m.Areas[x, y] = new Area(textures["road"], false);
                }
            }

            Map mapski = TowerDefense.ToolKit.Parser.ParseMapFile("map.txt");
            m.Areas = mapski.Areas;
            m.Route = mapski.Route;

            Player p = new Player();

            Tower t = new Tower();
            t.Position = new Vector2(180, 170);
            t.Range = 200f;
            t.Direction = 1;

            Tower t1 = new Tower();
            t1.Position = new Vector2(120, 200);
            t1.Range = 200f;
            t1.Direction = 1;
            Projectile proj = new Projectile();
            proj.ProjectileSpeed = 2;
            t1.AttackCooldown = new TimeSpan(0, 0, 0,2);
            t.AttackCooldown = new TimeSpan(0, 0, 0,2);
            proj.Texture = textures["missile1"];
            
            proj.Height = 8;
            proj.Width = 8;
            proj.Damage = 26;
            proj.CurrentState = Projectile.ProjectileState.InAir;
            t.Munition = proj;
            t1.Munition = proj;
            //p.Towers.Add(t);
            //p.Towers.Add(t1);

            UI.Button b = new UI.Button(30, 100) { Position = new Vector2(400, 400), Texture = textures.First().Value, Visible = true, ButtonDownTexture = textures.Last().Value, ButtonMouseOverTexture = textures.First().Value };
            b.Click += new TowerDefense.UI.ButtonEventHandler(b_Click);
            UI.ButtonHandler.Buttons.Add(b);

            World.Player = p;
            World.Maps.Enqueue(mapski);
            // TODO: use this.Content to load your game content here
            /*for (int i = 0; i < 2000; i++)
            {
                Creep c = CreepFactory.CreateCreep(CreepTypes.GroundCreep,1);
                Random r = new Random(i);
                c.Position = new Vector2(r.Next(1000), r.Next(1000));
                c.Speed = r.NextDouble() + 0.1;
                World.Creeps.Add(c);
            }
            */
        }

        public void b_Click(object sender, TowerDefense.UI.ButtonEventArgs e)
        {
            for(int i = 0; i < 30; i++)
                CreepSpawner.Creeps.Enqueue(CreepFactory.CreateCreep(CreepTypes.GroundCreep, 1)); 
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // Seperate logic 
            switch (_gameState)
            {
                case GameState.TitleScreen:
                    break;
                case GameState.Menu:
                    break;
                case GameState.GamePlay:
                    break;
                case GameState.GameOver:
                    break;
            }

            // TODO: Add your update logic here

            if (Mouse.GetState().RightButton != MouseLastRightButtonState)
            {
                switch (Mouse.GetState().RightButton)
                {
                    case ButtonState.Pressed:
                        Tower t1 = new Tower();
                        t1.Position = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
                        t1.Range = 50f;
                        t1.Direction = 1;
                        Projectile proj = new Projectile();
                        proj.ProjectileSpeed = 4;
                        t1.AttackCooldown = new TimeSpan(0, 0, 0, 0, 1000);
                        proj.Texture = textures["vulcan-shot"];
                        proj.Width = 10;
                        proj.Height = 10;
                        proj.Damage = 0;
                        proj.Effects.Add(new DamageOverTime(10, new TimeSpan(0, 0, 0, 9)));
                        proj.CurrentState = Projectile.ProjectileState.InAir;
                        t1.Munition = proj;
                        World.Player.Towers.Add(t1);
                        break;
                    case ButtonState.Released:
                        break;
                }
                MouseLastRightButtonState = Mouse.GetState().RightButton;
            }


            if (Mouse.GetState().LeftButton != MouseLastLeftButtonState)
            {
                switch (Mouse.GetState().LeftButton)
                {
                    case ButtonState.Pressed:
                        Tower t1 = new Tower();
                        t1.Position = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
                        t1.Range = 100f;
                        t1.Direction = 1;
                        Projectile proj = new Projectile();
                        proj.ProjectileSpeed = 10;
                        t1.AttackCooldown = new TimeSpan(0, 0, 0, 0, 1000);
                        proj.Texture = textures["Mark"];
                        proj.Width = 20;
                        proj.Height = 20;
                        proj.Damage = 5;
                        proj.Effects.Add(new Slow(new TimeSpan(0,0,0,0,1000),0.2));
                        proj.CurrentState = Projectile.ProjectileState.InAir;
                        t1.Munition = proj;
                        World.Player.Towers.Add(t1);
                        break;
                    case ButtonState.Released:
                        break;
                }
                MouseLastLeftButtonState = Mouse.GetState().LeftButton;
            }

            if (Keyboard.GetState().IsKeyDown(Keys.M) != KeyboardMLastState)
            {
                if(Keyboard.GetState().IsKeyDown(Keys.M))
                {
                    Tower t1 = new Tower();
                    t1.Position = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
                    t1.Range = 150f;
                    t1.Direction = 1;
                    Projectile proj = new Projectile();
                    proj.ProjectileSpeed = 2;
                    t1.AttackCooldown = new TimeSpan(0, 0, 0, 0, 1300);
                    proj.Texture = textures["missile1"];
                    proj.Width = 8;
                    proj.Height = 8;
                    proj.Damage = 50;
                    proj.CurrentState = Projectile.ProjectileState.InAir;
                    t1.Munition = proj;
                    World.Player.Towers.Add(t1);
                }
                KeyboardMLastState = Keyboard.GetState().IsKeyDown(Keys.M);
            }

            UI.ButtonHandler.Update(gameTime);
            CreepSpawner.Update(gameTime);
            
            World.Update(gameTime);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            Vector2 fOrigin = sFont.MeasureString("XNA Tower Defense") / 2;
            spriteBatch.DrawString(sFont, "XNA Tower Defense", sFontPos + new Vector2(2, 2), Color.Black, 0, fOrigin, 1.0f, SpriteEffects.None, 0.9f);
            spriteBatch.DrawString(sFont, "XNA Tower Defense", sFontPos, Color.DarkKhaki, 0, fOrigin, 1.0f, SpriteEffects.None, 0.9f);

            UI.ButtonHandler.Draw(spriteBatch);

            World.Draw(spriteBatch);

            int fps = (int)Math.Round(1.0 / gameTime.ElapsedGameTime.TotalSeconds);

            spriteBatch.DrawString(sFont, "FPS: " + fps, new Vector2(500, 50), Color.Yellow);
            spriteBatch.End();
            
            base.Draw(gameTime);
        }
    }
}
